package com.threader.bo;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.GregorianCalendar;
import java.util.Observable;
import java.util.Random;

import com.threader.utils.ConstantRegistry;

public class People extends Observable {
	public static final int WORCKHOURBREAK 	= 50;
	public static final int MINHUNGRYLEVEL 	= 20;

	private Passport 		passport 		= null;
	private PeopleInformer 	peopleInformer 	= null;
	private PeopleThread 	peopleThread 	= null;

	private double 			helth 			= 70;
	private boolean 		needSleep 		= false;
	private double 			hungry 			= 20;
	private boolean 		signHungry 		= true;
	private double 			worckMinutesCount = 0;
	private int 			state 			= ConstantRegistry.DEAD;
	private double 			money 			= 0;



	private Time time;
	ActionListener timerListener;
	private Place.Post post; 

//	private double worckCount = 0;
	private int worckDayLength = ConstantRegistry.worckDayLength;
	private int dinnerLength = 1;
	private int worckingDayPreparationLength = 1;
	private int normalSleepLength = 8;
	private int beginWorckTimeHour = 8;
	private int beginWorckTimeMinute = 0;
	private int beginDinnerTime = 13;
	private double beginSleepHour = beginWorckTimeHour - worckingDayPreparationLength - normalSleepLength;
	private int minHourBreak = 2;
	private int hourBreakLength = 0;
	private ActionListener timeListener=new ActionListener() {
		public void actionPerformed(ActionEvent e) {
			if (getPeopleThread() == null) {
				createPeopleThread();
			} else {
				if (!getPeopleThread().isAlive()) {
					setPeopleThread(null);
					createPeopleThread();
				}
			}
		}
	};

	public People(Time t) {
		setTime(t);
	}

	public People(Time t, Passport p) {
		setTime(t);
		passport = p;
		setMoney((new Random().nextInt(8)+1)*10);
	}

	public String toString() {
		return passport.toString();
	}

	public void showPassport() {
		getPeopleInformer().Show();
	}

	public double getHelth() {
		return helth;
	}

	public void setHelth(double newHelth) {
		if (newHelth > 100) {
			this.helth = 100;
			this.needSleep = false;
		} else {
			if (newHelth < 0) {
				this.helth = 0;
				this.needSleep = true;
			} else{
				if(this.getEat()==0 && newHelth>this.helth)
					this.helth = newHelth-0.2;
				else
					this.helth = newHelth;
				if(this.helth<=30)
					this.needSleep = true;
			}
		}
		stateChanged();
	}

	public void setEat(double hungry) {
		if (hungry > 100) {
			this.setMoney(this.getMoney()-5*(hungry - this.hungry)/100);
			this.hungry = 100;
			this.signHungry = false;
		} else {
			if (hungry < 0) {
				this.hungry = 0;
				this.signHungry = true;
				setHelth(getHelth() - 0.25);
			} else {
				if(hungry > this.hungry){
					this.setMoney(this.getMoney()-5*(hungry - this.hungry)/100);
				}
				this.hungry = hungry;
				if (this.hungry <= 50)
					this.signHungry = true;
			}
		}
		stateChanged();
	}

	public double getEat() {
		return hungry;
	}

//	public Boolean iAmHungry() {
//		return hungry <= MINHUNGRYLEVEL;
//	}

	public Boolean needEat() {
		long nowHour = new Long(getTime().getHour());
		return ((nowHour >= getWorckBeginTimeHour() - worckingDayPreparationLength && this.signHungry) || this.signHungry)&&this.getMoney()>0;
	}

	public Boolean needSleep() {
		return this.needSleep;
	}
	public Boolean needHourBreak() {
		return this.worckMinutesCount>=WORCKHOURBREAK;
	}
	
	public void setState(int state) {
		this.state = state;
		stateChanged();
	}

	public Integer getState() {
		Integer nowState = state;
		long nowHour = new Long(getTime().getHour());
		if(getPost()!=null){
			long beginWorckHour = getWorckBeginTimeHour();
			long beginDinneerHour = getDinnerBeginTime();
			if (nowHour >= beginWorckHour && nowHour <= beginWorckHour + getWorckDayLength()) 
			{
				if (nowHour >= beginDinneerHour  && nowHour < beginDinneerHour + getDinnerLength()) 
				{
					nowState = ConstantRegistry.DINNER;
					if (needSleep()) nowState = ConstantRegistry.SLEEP;
					if (needEat()) nowState = ConstantRegistry.EATING;
				} else {
					nowState = ConstantRegistry.WORCKING;
					if (needHourBreak()) nowState = ConstantRegistry.HOURBREAK;
				}
			} else {
				if (nowHour>=beginSleepHour && nowHour < beginWorckHour - worckingDayPreparationLength) 
				{
					nowState = ConstantRegistry.SLEEP;
					if (needEat()) nowState = ConstantRegistry.EATING;
				} else {
					nowState = ConstantRegistry.IDLE;
					if (needSleep()) nowState = ConstantRegistry.SLEEP;
					if (needEat()) nowState = ConstantRegistry.EATING;
				}
			}
		}else{
			nowState = ConstantRegistry.WORCKSEARCH;
			if (needSleep()) nowState = ConstantRegistry.SLEEP;
			if (needEat()) nowState = ConstantRegistry.EATING;
		}

		if (nowState != state) setState(nowState);
		return state;
	}

//	public double getWorckCount() {
//		return worckCount;
//	}

	private void setWorckCount() {
//		this.worckCount = worckCount;
		if(getPost()!=null){
			setWorckMinutesCount(getWorckMinutesCount() + getTime().interval/Time.MINUTE);
			getPost().getWorckPlace().setExecuted(getPost().getWorckPlace().getExecuted() + getHelth() / 100);
		}else{
			
		}

		//		if(peopleInformer!=null)getPeopleInformer().showWorckCount(new BigDecimal(worckCount).setScale(3, BigDecimal.ROUND_HALF_UP) + "");
		// setMotivation(getMotivation()-1);
	}

	public void setWorckMinutesCount(double worckMinutesCount) {
		this.worckMinutesCount = worckMinutesCount;
	}

	public double getWorckMinutesCount() {
		return worckMinutesCount;
	}

	public void setHourBreakLength(int hourBreakLength) {
		this.hourBreakLength = hourBreakLength;
		if(this.hourBreakLength == minHourBreak){
			this.worckMinutesCount=0;
			this.hourBreakLength = 0;
		}
	}

	public int getHourBreakLength() {
		return hourBreakLength;
	}

	public String getStateName() {
		return ConstantRegistry.statesNames[this.state];
	}


	public void setPeopleThread(PeopleThread peopleThread) {
		if (peopleThread == null)
			getPeopleThread().quit();
		this.peopleThread = peopleThread;
		if (this.peopleThread != null && getTime().isRunning())
			getPeopleThread().start();
	}

	public PeopleThread getPeopleThread() {
		return peopleThread;
	}

	public void setBeginWorckTimeHour(Integer beginWorckTimeHour) {
		this.beginWorckTimeHour = beginWorckTimeHour;
		this.beginDinnerTime = beginWorckTimeHour + this.getWorckDayLength() / 2;
		this.beginSleepHour = beginWorckTimeHour - worckingDayPreparationLength - normalSleepLength;
		stateChanged();
	}

	public Integer getWorckBeginTimeHour() {
		return beginWorckTimeHour;
	}

	public void setBeginWorckTimeMinute(Integer beginWorckTimeMinute) {
		this.beginWorckTimeMinute = beginWorckTimeMinute;
		stateChanged();
	}

	public Integer getWorckBeginTimeMinute() {
		return beginWorckTimeMinute;
	}

	public void setBeginDinnerTime(Integer beginDinnerTime) {
		this.beginDinnerTime = beginDinnerTime;
	}

	public Integer getDinnerBeginTime() {
		return this.beginDinnerTime;
	}

	public void setWorckDayLength(Integer worckDayLength) {
		this.worckDayLength = worckDayLength;
	}

	public Integer getWorckDayLength() {
		return worckDayLength;
	}

	public void setDinnerLength(Integer dinnerLength) {
		this.dinnerLength = dinnerLength;
	}

	public Integer getDinnerLength() {
		return dinnerLength;
	}

	public Integer getAge(){
		GregorianCalendar gc = new GregorianCalendar();
		gc.setTimeInMillis(getTime().getCurrentDate());
		int currentYear = gc.get(GregorianCalendar.YEAR);

		gc.setTimeInMillis(this.passport.birthDay);
		return currentYear - gc.get(GregorianCalendar.YEAR);
	}
	
	public PeopleThread createPeopleThread() {
		if (peopleThread == null) {
			setPeopleThread(new PeopleThread(this));
		}
		return peopleThread;
	}

	public void stateChanged() {
		setChanged();
		notifyObservers();
	}

	public void log(String string){
		if(peopleInformer!=null) getPeopleInformer().log(string);
	}
	
	public void setPeopleInformer(PeopleInformer peopleInformer) {
		this.peopleInformer = peopleInformer;
	}

	public PeopleInformer getPeopleInformer() {
		if(this.peopleInformer==null)
			setPeopleInformer(new PeopleInformer(this));
		return peopleInformer;
	}

	public void setPost(Place.Post post) {
		if(post==null && this.post!=null){
			this.post.delPeople(this);
		}
		this.post = post;
		stateChanged();
	}

	public Place.Post getPost() {
		return post;
	}

	public double getMoney() {
		return money;
	}

	public void setMoney(double money) {
		this.money = money;
	}

	private void setTime(Time time) {
		this.time = time;
		if(getTime()!=null){
			getTime().addActionListener(timeListener);
		}else{
			getTime().removeActionListener(timeListener);
		}
	}

	public Time getTime(){
		return this.time;
	}
	
	public void action() {
		Integer oldState = state;
		switch (getState()) {
		case ConstantRegistry.SLEEP:
			setHelth(getHelth() + 1.2);
			setEat(getEat() - 0.2);
			break;
		case ConstantRegistry.IDLE:
			setHelth(getHelth() - 0.2);
			setEat(getEat() - 1);
			break;
		case ConstantRegistry.WORCKING:
			setHelth(getHelth() - 0.5);
			setWorckCount();
			setEat(getEat() - 1);
			break;
		case ConstantRegistry.WORCKSEARCH:
			setHelth(getHelth() - 0.5);
			setWorckCount();
			setEat(getEat() - 1);
			break;
		case ConstantRegistry.HOURBREAK:
			setHelth(getHelth() - 0.1);
			setHourBreakLength(getHourBreakLength()+1);
			setEat(getEat() - 1);
			break;
		case ConstantRegistry.DINNER:
			setHelth(getHelth() - 0.1);
			setEat(getEat() - 1);
			break;
		case ConstantRegistry.EATING:
			setHelth(getHelth() - 0.2);
			setEat(getEat() + 20);
			break;
		}
		if (oldState != state)
			log(getTime().getCurrentTime() + " " + ConstantRegistry.statesNames[state]);

//		if (this.state == SLEEP) {
//			setHelth(getHelth() + 1.2);
//		}else
//			setHelth(getHelth() - 0.5);

	}

//	/**
//	 * @param args
//	 */
//	public static void main(String[] args) {
////System.out.println(new Long("01.01.2005"));
//	}

	public void kill() {
		getTime().removeActionListener(timerListener);
		
		if(getPost()!=null)
			getPost().delPeople(this);
		
		if(peopleInformer!=null)
			getPeopleInformer().dispose();

		if(getPeopleThread()!=null){
			getPeopleThread().quit();
		}
		
	}

}
